<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>Linux下如何在数据链路层接收原始数据包 - whowin - 发表我个人原创作品的技术博客</title>
  <meta name="renderer" content="webkit" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>

<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />

<meta name="theme-color" content="#f8f5ec" />
<meta name="msapplication-navbutton-color" content="#f8f5ec">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="#f8f5ec">


<meta name="author" content="whowin" /><meta name="description" content="大多数的网络编程都是在应用层接收数据和发送数据的，程序员无需关注报文的各种报头，网络协议栈会解决这些问题，本文介绍在数据链路层的网络编程方法，介绍如何在数据链路层直接接收从物理层发过来的原始数据包，要得到数据，必须自己解开数据链路层、网络层和传输层的报头，文章给出了一个完整的范例程序，希望本文能帮助读者对网络通信有更深刻的理解；阅读本文需要具备基本的使用socket进行网络编程的能力，熟悉OSI的网络模型，本文对初学者有一定的难度。
" /><meta name="keywords" content="linux, socket, hugo, dos" />






<meta name="generator" content="Hugo 0.97.3 with theme even" />


<link rel="canonical" href="https://whowin.gitee.io/post/blog/network/0002-link-layer-programming/" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">



<link href="/sass/main.min.e3fea119b1980e848b03dffbeddb11dd0fba483eed0e5f11870fb8e31f145bbd.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.css" integrity="sha256-7TyXnr2YU040zfSP+rEcz29ggW4j56/ujTPwjMzyqFY=" crossorigin="anonymous">


<meta property="og:title" content="Linux下如何在数据链路层接收原始数据包" />
<meta property="og:description" content="大多数的网络编程都是在应用层接收数据和发送数据的，程序员无需关注报文的各种报头，网络协议栈会解决这些问题，本文介绍在数据链路层的网络编程方法，介绍如何在数据链路层直接接收从物理层发过来的原始数据包，要得到数据，必须自己解开数据链路层、网络层和传输层的报头，文章给出了一个完整的范例程序，希望本文能帮助读者对网络通信有更深刻的理解；阅读本文需要具备基本的使用socket进行网络编程的能力，熟悉OSI的网络模型，本文对初学者有一定的难度。" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://whowin.gitee.io/post/blog/network/0002-link-layer-programming/" /><meta property="article:section" content="post" />
<meta property="article:published_time" content="2022-12-07T16:43:29+08:00" />
<meta property="article:modified_time" content="2022-12-07T16:43:29+08:00" />

<meta itemprop="name" content="Linux下如何在数据链路层接收原始数据包">
<meta itemprop="description" content="大多数的网络编程都是在应用层接收数据和发送数据的，程序员无需关注报文的各种报头，网络协议栈会解决这些问题，本文介绍在数据链路层的网络编程方法，介绍如何在数据链路层直接接收从物理层发过来的原始数据包，要得到数据，必须自己解开数据链路层、网络层和传输层的报头，文章给出了一个完整的范例程序，希望本文能帮助读者对网络通信有更深刻的理解；阅读本文需要具备基本的使用socket进行网络编程的能力，熟悉OSI的网络模型，本文对初学者有一定的难度。"><meta itemprop="datePublished" content="2022-12-07T16:43:29+08:00" />
<meta itemprop="dateModified" content="2022-12-07T16:43:29+08:00" />
<meta itemprop="wordCount" content="5620">
<meta itemprop="keywords" content="Linux,Socket,网络编程,数据链路层编程,raw socket," /><meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="Linux下如何在数据链路层接收原始数据包"/>
<meta name="twitter:description" content="大多数的网络编程都是在应用层接收数据和发送数据的，程序员无需关注报文的各种报头，网络协议栈会解决这些问题，本文介绍在数据链路层的网络编程方法，介绍如何在数据链路层直接接收从物理层发过来的原始数据包，要得到数据，必须自己解开数据链路层、网络层和传输层的报头，文章给出了一个完整的范例程序，希望本文能帮助读者对网络通信有更深刻的理解；阅读本文需要具备基本的使用socket进行网络编程的能力，熟悉OSI的网络模型，本文对初学者有一定的难度。"/>

<!--[if lte IE 9]>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20170427/classList.min.js"></script>
<![endif]-->

<!--[if lt IE 9]>
  <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->

  <script async src="/js/busuanzi.pure.mini.js"></script><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9724909319263152"
     crossorigin="anonymous"></script>


</head>
<body>
  <div id="mobile-navbar" class="mobile-navbar">
  <div class="mobile-header-logo">
    <a href="/" class="logo">WhoWin</a>
  </div>
  <div class="mobile-navbar-icon">
    <span></span>
    <span></span>
    <span></span>
  </div>
</div>
<nav id="mobile-menu" class="mobile-menu slideout-menu">
  <ul class="mobile-menu-list">
    <a href="/">
        <li class="mobile-menu-item">首页</li>
      </a><a href="/post/">
        <li class="mobile-menu-item">文章归档</li>
      </a><a href="/article-categories/categories/">
        <li class="mobile-menu-item">文章分类</li>
      </a><a href="/tags/">
        <li class="mobile-menu-item">文章标签</li>
      </a><a href="/about/about/">
        <li class="mobile-menu-item">关于</li>
      </a>
  </ul>

  


</nav>

  <div class="container" id="mobile-panel">
    <header id="header" class="header">
        <div class="logo-wrapper">
  <a href="/" class="logo">WhoWin</a>
  
  <div style="position:absolute; left: 80px; top: 75px; color: crimson">
      ———开源和分享是技术发展的源泉和动力；本博客所有文章均为原创
  </div>
</div>





<nav class="site-navbar">
  <ul id="menu" class="menu">
    <li class="menu-item">
        <a class="menu-item-link" href="/">首页</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/post/">文章归档</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/article-categories/categories/">文章分类</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/tags/">文章标签</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/about/about/">关于</a>
      </li>
  </ul>
</nav>

    </header>

    <main id="main" class="main">
      <div class="content-wrapper">
        <div id="content" class="content">
          <article class="post">
    
    <header class="post-header">
      <h1 class="post-title">Linux下如何在数据链路层接收原始数据包</h1>

      <div class="post-meta">
        <span class="post-time"> 2022-12-07 </span>
        <div class="post-category">
            <a href="/categories/linux/"> Linux </a>
            <a href="/categories/c-language/"> C Language </a>
            <a href="/categories/network/"> Network </a>
            </div>
        
      </div>
    </header>

    <div class="post-toc" id="post-toc">
  <h2 class="post-toc-title">文章目录</h2>
  <div class="post-toc-content always-active">
    <nav id="TableOfContents">
  <ul>
    <li>
      <ul>
        <li><a href="#1-概述">1. 概述</a></li>
        <li><a href="#2-socket编程">2. socket编程</a></li>
        <li><a href="#3-raw-socket">3. raw socket</a></li>
        <li><a href="#4-数据报的报头">4. 数据报的报头</a></li>
        <li><a href="#5-使用-raw-socket-接收数据">5. 使用 raw socket 接收数据</a></li>
        <li><a href="#欢迎订阅-网络编程专栏httpsblogcsdnnetwhowincategory_12180345html"><strong>欢迎订阅 <a href="https://blog.csdn.net/whowin/category_12180345.html">『网络编程专栏』</a></strong></a></li>
      </ul>
    </li>
  </ul>
</nav>
  </div>
</div>
    <div class="post-content">
      <p>大多数的网络编程都是在应用层接收数据和发送数据的，程序员无需关注报文的各种报头，网络协议栈会解决这些问题，本文介绍在数据链路层的网络编程方法，介绍如何在数据链路层直接接收从物理层发过来的原始数据包，要得到数据，必须自己解开数据链路层、网络层和传输层的报头，文章给出了一个完整的范例程序，希望本文能帮助读者对网络通信有更深刻的理解；阅读本文需要具备基本的使用socket进行网络编程的能力，熟悉OSI的网络模型，本文对初学者有一定的难度。</p>
<h2 id="1-概述">1. 概述</h2>
<ul>
<li>linux下进行网络编程通常都是使用socket在应用层接收和发送数据；</li>
<li>本文介绍如何绕过数据链路层、网络层和传输层对数据包的处理，直接从数据链路层接收从物理层发过来的原始数据；</li>
<li>本文所介绍的内容在实际编程中很少会用到，但希望对读者理解网络结构和协议能有帮助；</li>
<li>本文会提供了直接从数据链路层接收数据的范例程序，源代码在ubuntu 20.04下编译运行成功；</li>
<li>本文可能并不适合初学者，但并不妨碍初学者收藏此文，以便在今后学习。</li>
</ul>
<h2 id="2-socket编程">2. socket编程</h2>
<ul>
<li>
<p>在看下面的内容之前还是要简单地回顾一下TCP/IP的五层网络模型(OSI 七层架构的简化版)</p>
<ol>
<li>应用层</li>
<li>传输层</li>
<li>网络层</li>
<li>数据链路层</li>
<li>物理层</li>
</ol>
</li>
<li>
<p>使用socket进行网络编程时，我们通常只需要关心需要发送的数据，数据发送后，要发送的数据将从应用层向下传递</p>
<ul>
<li>在TCP/UDP(传输)层加入一个TCP头</li>
<li>在IP(网络)层加上一个IP头</li>
<li>在数据链路层加上一个以太网头</li>
<li>交给物理层传输</li>
</ul>
</li>
<li>
<p>当我们在应用层进行socket编程时，我们通常会这样发送数据(以UDP为例)：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="p">......</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">addr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">sock</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_DGRAM</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">......</span>
</span></span><span class="line"><span class="cl"><span class="n">addr</span><span class="p">.</span><span class="n">sin_family</span> <span class="o">=</span> <span class="n">AF_INET</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">addr</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">.</span><span class="n">s_addr</span> <span class="o">=</span> <span class="n">inet_addr</span><span class="p">(</span><span class="n">DST_IP</span><span class="p">);</span>       <span class="c1">// 目的IP
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">addr</span><span class="p">.</span><span class="n">sin_port</span> <span class="o">=</span> <span class="n">htons</span><span class="p">(</span><span class="n">PORT</span><span class="p">);</span>                    <span class="c1">// 端口号
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">.....</span>
</span></span><span class="line"><span class="cl"><span class="n">sendto</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">DATA</span><span class="p">,</span> <span class="n">DATA_LEN</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">addr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr_in</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="n">close</span><span class="p">(</span><span class="n">fd</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>当我们把DATA给sendto(&hellip;&hellip;)以后，会发生什么呢？</p>
<ol>
<li>数据从应用层被送到传输层，传输层给这个数据加上一个UDP 头；</li>
<li>(UDP头+DATA)从传输层被送到网络层，IP协议会给数据包再加上一个IP头；</li>
<li>(IP头+UDP头+DATA)从网络层被送到了数据链路层，数据链路层的以太网协议会给这个数据包加上一个以太网头；</li>
<li>(以太网头+IP头+UDP头+DATA)从数据链路层被送到了物理层，数据就被发送走了。</li>
</ol>
<p><img src="https://whowin.gitee.io/images/180002/sending_data_from_app_with_socket.png" alt="使用socket从应用程序发送数据的过程"></p>
<center><b>图1：使用socket从应用程序发送数据的过程</b></center>
</li>
</ul>
<hr>
<ul>
<li>
<p>当我们在应用层进行socket编程时，我们通常会这样接收数据(以UDP为例)：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="p">......</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">addr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">addr_len</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr_in</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">sock</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_DGRAM</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">......</span>
</span></span><span class="line"><span class="cl"><span class="n">addr</span><span class="p">.</span><span class="n">sin_family</span> <span class="o">=</span> <span class="n">AF_INET</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">addr</span><span class="p">.</span><span class="n">sin_port</span> <span class="o">=</span> <span class="n">htons</span><span class="p">(</span><span class="n">PORT</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">addr</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">.</span><span class="n">s_addr</span> <span class="o">=</span> <span class="n">inet_addr</span><span class="p">(</span><span class="n">SERVER_IP</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">......</span>
</span></span><span class="line"><span class="cl"><span class="n">recvfrom</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">buffer</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">addr</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">addr_len</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">......</span>
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>当我们调用recvfrom()函数并成功返回时，都发生了什么事情呢？</p>
<ol>
<li>原始数据包(以太网头+IP头+UDP头+DATA)通过网卡驱动程序发送到数据链路层；</li>
<li>数据链路层从原始数据包中提取出以太网头，数据包的其余部分发送给网络层(IP头+UDP头+DATA)；</li>
<li>网络层从数据中提取出IP头，其余部分交给传输层(UDP头+DATA)；</li>
<li>传输层从数据中提取出UDP头，其余部分交给应用程序(DATA)；</li>
<li>所以我们在应用层收到的就只有数据了，报头已经被各协议层提取出来</li>
</ol>
<p><img src="https://whowin.gitee.io/images/180002/receiving_data_in_app_with_socket.png" alt="在应用程序中用socket接收数据的过程"></p>
<center><b>图2：在应用程序中用socket接收数据的过程</b></center>
</li>
</ul>
<hr>
<ul>
<li>很显然，在应用层进行网络编程，我们不需要关心各协议层的报头，各层的协议栈会为我们处理好所有报头；</li>
<li>但这样的编程显然也是受限的，除了TCP和UDP以外，你还知道有什么其它的网络通信形式吗？这种在应用层的编程仅能收到发给这台机器的数据，而且在你收到的数据中，并没有源和目的地址的任何信息。</li>
<li>从图1和图2可以看出，当我们需要在传输层编程时，实际上就是比在应用层编程多了一个UDP(TCP)头；同理，当我们需要在网络层编程时，也就是比在传输层编程多加一个IP头；</li>
<li>本文介绍在数据链路层编程，与在应用层的网络编程相比，只是要多封装(提取)三个数据头：以太网头、IP头、UDP(TCP)头</li>
</ul>
<h2 id="3-raw-socket">3. raw socket</h2>
<ul>
<li>
<p>raw socket也是一种socket，常用于接收原始数据包，所谓原始数据包指的是从物理层直接传送出来的数据包；使用raw socket可以绕过通常的TCP/IP处理流程，在应用程序中直接收到原始数据包(见图3)。使用raw socket编程，并不需要对Linux内核有深入的了解。</p>
<p><img src="https://whowin.gitee.io/images/180002/app_receive_data_with_raw_socket.png" alt="在应用程序中使用raw socket接收数据"></p>
<center><b>图3：在应用程序中使用raw socket接收数据</b></center>
</li>
</ul>
<hr>
<ul>
<li>打开raw socket
<ul>
<li>
<p>和普通socket一样，打开一个raw socket，必须要知道三件事：socket family、socket type 和 protocol；</p>
</li>
<li>
<p>对raw socket而言，socket family为AF_PACKET，socket type为SOCK_RAW；</p>
</li>
<li>
<p>接收数据时，protocol请参考头文件if_ether.h；接收所有数据包，protocol使用宏ETH_P_ALL；接收IP数据包，protocol使用宏ETH_P_IP。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">sock_raw</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">sock_raw</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_PACKET</span><span class="p">,</span> <span class="n">SOCK_RAW</span><span class="p">,</span> <span class="n">htons</span><span class="p">(</span><span class="n">ETH_P_ALL</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">sock_raw</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">printf</span><span class="p">(</span><span class="s">&#34;error in socket</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>发送数据时，protocol要参考头文件in.h，通常protocol使用IPPROTO_RAW；</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">sock_raw</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_PACKET</span><span class="p">,</span> <span class="n">SOCK_RAW</span><span class="p">,</span> <span class="n">IPPROTO_RAW</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">sock_raw</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">printf</span><span class="p">(</span><span class="s">&#34;error in socket&#34;</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div></li>
</ul>
</li>
</ul>
<h2 id="4-数据报的报头">4. 数据报的报头</h2>
<ul>
<li>
<p>前面提过，应用程序使用socket发送数据(以UDP为例)的时候，在经过传输层时，要增加一个UDP头，经过网络层时，要再加上一个IP头，在经过数据链路层时，还要加上一个以太网头，然后才能交给物理层发送，见图1；</p>
</li>
<li>
<p>同样，应用程序使用socket接收数据(以UDP为例)时，数据从物理层经过数据链路层时，将去除以太网头，在经过网络层时，要去掉IP头，在经过传输层时，还要去掉UDP头，所以到达应用程序时，就只有数据了，见图2；</p>
</li>
<li>
<p>当使用raw_socket在数据链路层编程时，收到的数据需要自行解开以太网头、IP头、UDP头；而发送数据时，需要自行在数据上封装UDP头、IP头和以太网头；</p>
</li>
<li>
<p><strong>网络报文的报头的通用定义</strong></p>
<ul>
<li>网络报文的报头分为三个部分：传输层的传输层协议头、网络层的网络层协议头和数据链路层的以太网头，见图4；</li>
</ul>
<p><img src="https://whowin.gitee.io/images/180002/a_generic_representation_of_a_network_packet.png" alt="网络报头的通用定义"></p>
<center><b>图4：网络报头的通用定义</b></center>
<hr>
<ul>
<li>以下仅就本文范例中用到的报头结构做一个简单说明。</li>
</ul>
</li>
<li>
<p><strong>数据链路层的以太网头</strong></p>
<ul>
<li>以太网报头定义在头文件linux/if_ether.h中：
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">ethhdr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">char</span>  <span class="n">h_dest</span><span class="p">[</span><span class="n">ETH_ALEN</span><span class="p">];</span>    <span class="cm">/* destination eth addr  */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">char</span>  <span class="n">h_source</span><span class="p">[</span><span class="n">ETH_ALEN</span><span class="p">];</span>  <span class="cm">/* source ether addr  */</span>
</span></span><span class="line"><span class="cl">    <span class="n">__be16</span>         <span class="n">h_proto</span><span class="p">;</span>             <span class="cm">/* packet type ID field  */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="n">__attribute__</span><span class="p">((</span><span class="n">packed</span><span class="p">));</span>
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>h_dest字段为目的MAC地址，h_source字段为源MAC地址；</li>
<li>h_proto表示当前数据包在网络层使用的协议，Linux支持的协议在头文件linux/if_ether.h中定义；通常在网络层使用的IP协议，这个字段的值是0x0800(ETH_P_IP)；</li>
</ul>
</li>
<li>
<p><strong>网络层的 IP 头</strong></p>
<ul>
<li>
<p>IP(Internet Protocol)协议是网络层最常用的协议；</p>
</li>
<li>
<p>IP报头定义在头文件linux/ip.h中；</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">iphdr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="cp">#if defined(__LITTLE_ENDIAN_BITFIELD)
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>    <span class="n">__u8</span>  <span class="nl">ihl</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nl">version</span><span class="p">:</span><span class="mi">4</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="cp">#elif defined (__BIG_ENDIAN_BITFIELD)
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>    <span class="n">__u8</span>  <span class="nl">version</span><span class="p">:</span><span class="mi">4</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nl">ihl</span><span class="p">:</span><span class="mi">4</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span><span class="line"><span class="cl"><span class="cp">#error  &#34;Please fix &lt;asm/byteorder.h&gt;&#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>    <span class="n">__u8</span>    <span class="n">tos</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">__be16</span>  <span class="n">tot_len</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">__be16</span>  <span class="n">id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">__be16</span>  <span class="n">frag_off</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">__u8</span>    <span class="n">ttl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">__u8</span>    <span class="n">protocol</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">__sum16</span> <span class="n">check</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">__be32</span>  <span class="n">saddr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">__be32</span>  <span class="n">daddr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/*The options start here. */</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><img src="https://whowin.gitee.io/images/180002/ip_header.png" alt="IP 报头"></p>
<center><b>图5：IP 报头</b></center>
</li>
</ul>
<hr>
<ul>
<li>version - IPV4时，version=4</li>
<li>ihl(Internet Header Length) - 报头的长度，表示报头占用多少个32 bits字(4 字节)，IP报头最少要20 bytes，也就是ihl=5，最长可以是60 bytes，也就是ihl=15；ihl x 4就是IP报头占用的字节数；</li>
<li>tos - 这个字段通常并不使用，可以填0；</li>
<li>tot_len(Total Length) - 报文全长，包括IP头和IP payload，单位是字节；</li>
<li>id - IP报文的唯一标识，同一个IP报文分片传输时，其id是一样的，便于分片重组；</li>
<li>frag_off(Fragment Offest) - 其中bit 0、bit 1 和 bit 2用于控制和识别分片，bit 3 - 15这13个bit表示每个分片相对于原始报文开头的偏移量，以8字节作单位；</li>
<li>ttl(Time To Live) - 这个字段是为了防止报文在互联网上永远存在(比如进入路由环路)，在发送报文时设置这个值，最大255，通常设置为64，每经过一个路由器，该值将减1，当为0时，该报文将被丢弃；</li>
<li>protocol - 该字段定义了在传输层所用的协议，协议号列表文件在/etc/protocols文件中，UDP为17，TCP为6，其取值定义在头文件linux/in.h中；</li>
<li>check - IP头的检查和，不包括payload，关于IP头的检查和的计算方法有专门的文章介绍，开一参考<a href="https://www.thegeekstuff.com/2012/05/ip-header-checksum/">这里</a>，也可以参考本文的范例源代码；</li>
<li>saddr - 源IP地址，此字段是一个4字节的IP地址转为二进制并拼在一起所得到的32位值；例如：10.9.8.7是00001010 00001001 00001000 00000111</li>
<li>daddr - 目的IP地址，表示方法与saddr一样；</li>
<li>当数据链路层的h_proto字段为ETH_P_IP时，表示网络层使用的是IP(Internet Protocol)协议；实际上，网络层支持一些其它的协议，比如：Ethernet Loopback、Xerox PUP等；</li>
<li>网络层和传输层支持的协议可以在文件/etc/protocols中查看。</li>
</ul>
</li>
<li>
<p><strong>传输层的 UDP 头</strong></p>
<ul>
<li>UDP(User Datagram Protocol)是传输层最常用的协议之一；</li>
<li>UDP头定义在头文件linux/udp.h中；
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">udphdr</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">__be16</span>	<span class="n">source</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">__be16</span>	<span class="n">dest</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">__be16</span>	<span class="n">len</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">__sum16</span>	<span class="n">check</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>source - 来源连接端口号，可选项，如果不使用，填充0；</li>
<li>dest - 目的连接端口号；</li>
<li>len - 报文长度；</li>
<li>check - 报头的校验和，在IPv4中是可选的，IPv6中是强制的，如果不使用，应填充0；校验和的计算还涉及到UDP的伪头部，请参考<a href="https://www.ques10.com/p/10930/how-is-checksum-computed-in-udp-1/">相关文章</a>；</li>
</ul>
</li>
</ul>
<h2 id="5-使用-raw-socket-接收数据">5. 使用 raw socket 接收数据</h2>
<ul>
<li>
<p>把上面介绍的内容综合起来就可以编写出一个在数据链路层使用raw socket接收原始数据包的程序了；</p>
</li>
<li>
<p>以接收一个UDP数据包为例说明接收数据的步骤：</p>
<ol>
<li>打开一个raw socket；</li>
<li>在内存中分配一个buffer，并接收数据；</li>
<li>提取数据链路层的以太网协议头；</li>
<li>提取解开网络层的IP协议头；</li>
<li>提取解开传输层的UDP协议头；</li>
<li>提取收到的数据</li>
</ol>
</li>
<li>
<p>下面是一个监听UDP数据包的范例程序，文件名receive_udp_packet.c</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">  1
</span><span class="lnt">  2
</span><span class="lnt">  3
</span><span class="lnt">  4
</span><span class="lnt">  5
</span><span class="lnt">  6
</span><span class="lnt">  7
</span><span class="lnt">  8
</span><span class="lnt">  9
</span><span class="lnt"> 10
</span><span class="lnt"> 11
</span><span class="lnt"> 12
</span><span class="lnt"> 13
</span><span class="lnt"> 14
</span><span class="lnt"> 15
</span><span class="lnt"> 16
</span><span class="lnt"> 17
</span><span class="lnt"> 18
</span><span class="lnt"> 19
</span><span class="lnt"> 20
</span><span class="lnt"> 21
</span><span class="lnt"> 22
</span><span class="lnt"> 23
</span><span class="lnt"> 24
</span><span class="lnt"> 25
</span><span class="lnt"> 26
</span><span class="lnt"> 27
</span><span class="lnt"> 28
</span><span class="lnt"> 29
</span><span class="lnt"> 30
</span><span class="lnt"> 31
</span><span class="lnt"> 32
</span><span class="lnt"> 33
</span><span class="lnt"> 34
</span><span class="lnt"> 35
</span><span class="lnt"> 36
</span><span class="lnt"> 37
</span><span class="lnt"> 38
</span><span class="lnt"> 39
</span><span class="lnt"> 40
</span><span class="lnt"> 41
</span><span class="lnt"> 42
</span><span class="lnt"> 43
</span><span class="lnt"> 44
</span><span class="lnt"> 45
</span><span class="lnt"> 46
</span><span class="lnt"> 47
</span><span class="lnt"> 48
</span><span class="lnt"> 49
</span><span class="lnt"> 50
</span><span class="lnt"> 51
</span><span class="lnt"> 52
</span><span class="lnt"> 53
</span><span class="lnt"> 54
</span><span class="lnt"> 55
</span><span class="lnt"> 56
</span><span class="lnt"> 57
</span><span class="lnt"> 58
</span><span class="lnt"> 59
</span><span class="lnt"> 60
</span><span class="lnt"> 61
</span><span class="lnt"> 62
</span><span class="lnt"> 63
</span><span class="lnt"> 64
</span><span class="lnt"> 65
</span><span class="lnt"> 66
</span><span class="lnt"> 67
</span><span class="lnt"> 68
</span><span class="lnt"> 69
</span><span class="lnt"> 70
</span><span class="lnt"> 71
</span><span class="lnt"> 72
</span><span class="lnt"> 73
</span><span class="lnt"> 74
</span><span class="lnt"> 75
</span><span class="lnt"> 76
</span><span class="lnt"> 77
</span><span class="lnt"> 78
</span><span class="lnt"> 79
</span><span class="lnt"> 80
</span><span class="lnt"> 81
</span><span class="lnt"> 82
</span><span class="lnt"> 83
</span><span class="lnt"> 84
</span><span class="lnt"> 85
</span><span class="lnt"> 86
</span><span class="lnt"> 87
</span><span class="lnt"> 88
</span><span class="lnt"> 89
</span><span class="lnt"> 90
</span><span class="lnt"> 91
</span><span class="lnt"> 92
</span><span class="lnt"> 93
</span><span class="lnt"> 94
</span><span class="lnt"> 95
</span><span class="lnt"> 96
</span><span class="lnt"> 97
</span><span class="lnt"> 98
</span><span class="lnt"> 99
</span><span class="lnt">100
</span><span class="lnt">101
</span><span class="lnt">102
</span><span class="lnt">103
</span><span class="lnt">104
</span><span class="lnt">105
</span><span class="lnt">106
</span><span class="lnt">107
</span><span class="lnt">108
</span><span class="lnt">109
</span><span class="lnt">110
</span><span class="lnt">111
</span><span class="lnt">112
</span><span class="lnt">113
</span><span class="lnt">114
</span><span class="lnt">115
</span><span class="lnt">116
</span><span class="lnt">117
</span><span class="lnt">118
</span><span class="lnt">119
</span><span class="lnt">120
</span><span class="lnt">121
</span><span class="lnt">122
</span><span class="lnt">123
</span><span class="lnt">124
</span><span class="lnt">125
</span><span class="lnt">126
</span><span class="lnt">127
</span><span class="lnt">128
</span><span class="lnt">129
</span><span class="lnt">130
</span><span class="lnt">131
</span><span class="lnt">132
</span><span class="lnt">133
</span><span class="lnt">134
</span><span class="lnt">135
</span><span class="lnt">136
</span><span class="lnt">137
</span><span class="lnt">138
</span><span class="lnt">139
</span><span class="lnt">140
</span><span class="lnt">141
</span><span class="lnt">142
</span><span class="lnt">143
</span><span class="lnt">144
</span><span class="lnt">145
</span><span class="lnt">146
</span><span class="lnt">147
</span><span class="lnt">148
</span><span class="lnt">149
</span><span class="lnt">150
</span><span class="lnt">151
</span><span class="lnt">152
</span><span class="lnt">153
</span><span class="lnt">154
</span><span class="lnt">155
</span><span class="lnt">156
</span><span class="lnt">157
</span><span class="lnt">158
</span><span class="lnt">159
</span><span class="lnt">160
</span><span class="lnt">161
</span><span class="lnt">162
</span><span class="lnt">163
</span><span class="lnt">164
</span><span class="lnt">165
</span><span class="lnt">166
</span><span class="lnt">167
</span><span class="lnt">168
</span><span class="lnt">169
</span><span class="lnt">170
</span><span class="lnt">171
</span><span class="lnt">172
</span><span class="lnt">173
</span><span class="lnt">174
</span><span class="lnt">175
</span><span class="lnt">176
</span><span class="lnt">177
</span><span class="lnt">178
</span><span class="lnt">179
</span><span class="lnt">180
</span><span class="lnt">181
</span><span class="lnt">182
</span><span class="lnt">183
</span><span class="lnt">184
</span><span class="lnt">185
</span><span class="lnt">186
</span><span class="lnt">187
</span><span class="lnt">188
</span><span class="lnt">189
</span><span class="lnt">190
</span><span class="lnt">191
</span><span class="lnt">192
</span><span class="lnt">193
</span><span class="lnt">194
</span><span class="lnt">195
</span><span class="lnt">196
</span><span class="lnt">197
</span><span class="lnt">198
</span><span class="lnt">199
</span><span class="lnt">200
</span><span class="lnt">201
</span><span class="lnt">202
</span><span class="lnt">203
</span><span class="lnt">204
</span><span class="lnt">205
</span><span class="lnt">206
</span><span class="lnt">207
</span><span class="lnt">208
</span><span class="lnt">209
</span><span class="lnt">210
</span><span class="lnt">211
</span><span class="lnt">212
</span><span class="lnt">213
</span><span class="lnt">214
</span><span class="lnt">215
</span><span class="lnt">216
</span><span class="lnt">217
</span><span class="lnt">218
</span><span class="lnt">219
</span><span class="lnt">220
</span><span class="lnt">221
</span><span class="lnt">222
</span><span class="lnt">223
</span><span class="lnt">224
</span><span class="lnt">225
</span><span class="lnt">226
</span><span class="lnt">227
</span><span class="lnt">228
</span><span class="lnt">229
</span><span class="lnt">230
</span><span class="lnt">231
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;signal.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;malloc.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/socket.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/types.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;arpa/inet.h&gt;           // to avoid warning at inet_ntoa</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="cp">#include</span><span class="cpf">&lt;linux/if_packet.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;linux/in.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;linux/if_ether.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;linux/ip.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;linux/udp.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;linux/tcp.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="cp">#define LOG_FILE       &#34;udp_packets.log&#34;    </span><span class="c1">// log file name
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">ethhdr</span> <span class="o">*</span><span class="n">eth_hdr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">iphdr</span> <span class="o">*</span><span class="n">ip_hdr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">udphdr</span> <span class="o">*</span><span class="n">udp_hdr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/*****************************************************************************
</span></span></span><span class="line"><span class="cl"><span class="cm">* Function: unsigned int ethernet_header(unsigned char *buffer, int buflen)
</span></span></span><span class="line"><span class="cl"><span class="cm">* Description: Extracting the Ethernet header
</span></span></span><span class="line"><span class="cl"><span class="cm">*              struct ethhdr is defined in if_ether.h
</span></span></span><span class="line"><span class="cl"><span class="cm">* 
</span></span></span><span class="line"><span class="cl"><span class="cm">* Entry: buffer     data packet
</span></span></span><span class="line"><span class="cl"><span class="cm">*        buf_len    length of data packet
</span></span></span><span class="line"><span class="cl"><span class="cm">* Return: protocol of network layer or -1 when error
</span></span></span><span class="line"><span class="cl"><span class="cm">*****************************************************************************/</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">ethernet_header</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span><span class="p">,</span> <span class="kt">int</span> <span class="n">buf_len</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">buf_len</span> <span class="o">&lt;</span> <span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">ethhdr</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">printf</span><span class="p">(</span><span class="s">&#34;Wrong data packet.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">eth_hdr</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">ethhdr</span> <span class="o">*</span><span class="p">)(</span><span class="n">buffer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">ntohs</span><span class="p">(</span><span class="n">eth_hdr</span><span class="o">-&gt;</span><span class="n">h_proto</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*********************************************************************************
</span></span></span><span class="line"><span class="cl"><span class="cm">* Function: void log_ethernet_header(FILE *log_file, struct ethhdr *eth_hdr)
</span></span></span><span class="line"><span class="cl"><span class="cm">* Description: write ether header into log file
</span></span></span><span class="line"><span class="cl"><span class="cm">* 
</span></span></span><span class="line"><span class="cl"><span class="cm">* Entry:   log_file    log file object
</span></span></span><span class="line"><span class="cl"><span class="cm">*          eth_hdr     pointer of ethernet header structure
</span></span></span><span class="line"><span class="cl"><span class="cm">*********************************************************************************/</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">log_ethernet_header</span><span class="p">(</span><span class="n">FILE</span> <span class="o">*</span><span class="n">log_file</span><span class="p">,</span> <span class="k">struct</span> <span class="n">ethhdr</span> <span class="o">*</span><span class="n">eth_hdr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">Ethernet Header</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-Source MAC Address     : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">            <span class="n">eth_hdr</span><span class="o">-&gt;</span><span class="n">h_source</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">eth_hdr</span><span class="o">-&gt;</span><span class="n">h_source</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">eth_hdr</span><span class="o">-&gt;</span><span class="n">h_source</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> 
</span></span><span class="line"><span class="cl">            <span class="n">eth_hdr</span><span class="o">-&gt;</span><span class="n">h_source</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">eth_hdr</span><span class="o">-&gt;</span><span class="n">h_source</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span> <span class="n">eth_hdr</span><span class="o">-&gt;</span><span class="n">h_source</span><span class="p">[</span><span class="mi">5</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-Destination MAC Address: %.2X-%.2X-%.2X-%.2X-%.2X-%.2X</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">            <span class="n">eth_hdr</span><span class="o">-&gt;</span><span class="n">h_dest</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">eth_hdr</span><span class="o">-&gt;</span><span class="n">h_dest</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">eth_hdr</span><span class="o">-&gt;</span><span class="n">h_dest</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> 
</span></span><span class="line"><span class="cl">            <span class="n">eth_hdr</span><span class="o">-&gt;</span><span class="n">h_dest</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">eth_hdr</span><span class="o">-&gt;</span><span class="n">h_dest</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span> <span class="n">eth_hdr</span><span class="o">-&gt;</span><span class="n">h_dest</span><span class="p">[</span><span class="mi">5</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-Protocol               : 0X%04X</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">ntohs</span><span class="p">(</span><span class="n">eth_hdr</span><span class="o">-&gt;</span><span class="n">h_proto</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// ETH_P_IP = 0x0800, ETH_P_LOOP = 0X0060
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="cm">/********************************************************************************
</span></span></span><span class="line"><span class="cl"><span class="cm">* Function: unsigned int ip_header(unsigned char *buffer, int buf_len)
</span></span></span><span class="line"><span class="cl"><span class="cm">* Description: Extracting the IP header
</span></span></span><span class="line"><span class="cl"><span class="cm">*              struct iphdr is defined in ip.h
</span></span></span><span class="line"><span class="cl"><span class="cm">* 
</span></span></span><span class="line"><span class="cl"><span class="cm">* Entry: buffer     data packet
</span></span></span><span class="line"><span class="cl"><span class="cm">*        buf_len    length of data packet
</span></span></span><span class="line"><span class="cl"><span class="cm">* return: protocol of transport layer or -1 when error
</span></span></span><span class="line"><span class="cl"><span class="cm">********************************************************************************/</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">ip_header</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span><span class="p">,</span> <span class="kt">int</span> <span class="n">buf_len</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">buf_len</span> <span class="o">&lt;</span> <span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">ethhdr</span><span class="p">)</span> <span class="o">+</span> <span class="mi">20</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">printf</span><span class="p">(</span><span class="s">&#34;Wrong data packet.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ip_hdr</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">iphdr</span> <span class="o">*</span><span class="p">)(</span><span class="n">buffer</span> <span class="o">+</span> <span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">ethhdr</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">tot_len</span> <span class="o">=</span> <span class="n">ntohs</span><span class="p">(</span><span class="n">ip_hdr</span><span class="o">-&gt;</span><span class="n">tot_len</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">buf_len</span> <span class="o">&lt;</span> <span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">ethhdr</span><span class="p">)</span> <span class="o">+</span> <span class="n">tot_len</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">printf</span><span class="p">(</span><span class="s">&#34;Wrong data packet.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">ip_hdr</span><span class="o">-&gt;</span><span class="n">protocol</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="cm">/********************************************************************************
</span></span></span><span class="line"><span class="cl"><span class="cm">* Function: void log_ip_header(FILE *log_file, struct iphdr *ip_hdr)
</span></span></span><span class="line"><span class="cl"><span class="cm">* Description: write ip header into log file
</span></span></span><span class="line"><span class="cl"><span class="cm">* 
</span></span></span><span class="line"><span class="cl"><span class="cm">* Entry:   log_file        log file&#39;s handler
</span></span></span><span class="line"><span class="cl"><span class="cm">*          ip_hdr          the pointer of ip header structure
</span></span></span><span class="line"><span class="cl"><span class="cm">********************************************************************************/</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">log_ip_header</span><span class="p">(</span><span class="n">FILE</span> <span class="o">*</span><span class="n">log_file</span><span class="p">,</span> <span class="k">struct</span> <span class="n">iphdr</span> <span class="o">*</span><span class="n">ip_hdr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">source</span><span class="p">,</span> <span class="n">dest</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">memset</span><span class="p">(</span><span class="o">&amp;</span><span class="n">source</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">source</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="n">source</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">.</span><span class="n">s_addr</span> <span class="o">=</span> <span class="n">ip_hdr</span><span class="o">-&gt;</span><span class="n">saddr</span><span class="p">;</span>     
</span></span><span class="line"><span class="cl">    <span class="n">memset</span><span class="p">(</span><span class="o">&amp;</span><span class="n">dest</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">dest</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="n">dest</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">.</span><span class="n">s_addr</span> <span class="o">=</span> <span class="n">ip_hdr</span><span class="o">-&gt;</span><span class="n">daddr</span><span class="p">;</span>     
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">IP Header</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-Version               : %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span><span class="n">ip_hdr</span><span class="o">-&gt;</span><span class="n">version</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-Internet Header Length: %d DWORDS or %d Bytes</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span><span class="n">ip_hdr</span><span class="o">-&gt;</span><span class="n">ihl</span><span class="p">,</span> <span class="p">((</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)(</span><span class="n">ip_hdr</span><span class="o">-&gt;</span><span class="n">ihl</span><span class="p">))</span> <span class="o">*</span> <span class="mi">4</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-Type Of Service       : %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span><span class="n">ip_hdr</span><span class="o">-&gt;</span><span class="n">tos</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-Total Length          : %d  Bytes</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">ntohs</span><span class="p">(</span><span class="n">ip_hdr</span><span class="o">-&gt;</span><span class="n">tot_len</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-Identification        : %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">ntohs</span><span class="p">(</span><span class="n">ip_hdr</span><span class="o">-&gt;</span><span class="n">id</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-Time To Live          : %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span><span class="n">ip_hdr</span><span class="o">-&gt;</span><span class="n">ttl</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-Protocol              : %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="p">)</span><span class="n">ip_hdr</span><span class="o">-&gt;</span><span class="n">protocol</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-Header Checksum       : %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">ntohs</span><span class="p">(</span><span class="n">ip_hdr</span><span class="o">-&gt;</span><span class="n">check</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-Source IP             : %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">inet_ntoa</span><span class="p">(</span><span class="n">source</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-Destination IP        : %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">inet_ntoa</span><span class="p">(</span><span class="n">dest</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="cm">/************************************************************************
</span></span></span><span class="line"><span class="cl"><span class="cm">* Function: udp_header(FILE *log_file, struct iphdr *ip_hdr)
</span></span></span><span class="line"><span class="cl"><span class="cm">* Description: Extracting the UDP header
</span></span></span><span class="line"><span class="cl"><span class="cm">* 
</span></span></span><span class="line"><span class="cl"><span class="cm">* Entry:   log_file    log file
</span></span></span><span class="line"><span class="cl"><span class="cm">*          ip_hdr      pointer of IP header
</span></span></span><span class="line"><span class="cl"><span class="cm">************************************************************************/</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">udp_header</span><span class="p">(</span><span class="n">FILE</span> <span class="o">*</span><span class="n">log_file</span><span class="p">,</span> <span class="k">struct</span> <span class="n">iphdr</span> <span class="o">*</span><span class="n">ip_hdr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">UDP Header</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">udp_hdr</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">udphdr</span> <span class="o">*</span><span class="p">)((</span><span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">ip_hdr</span> <span class="o">+</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span><span class="n">ip_hdr</span><span class="o">-&gt;</span><span class="n">ihl</span> <span class="o">*</span> <span class="mi">4</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-Source Port     : %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">ntohs</span><span class="p">(</span><span class="n">udp_hdr</span><span class="o">-&gt;</span><span class="n">source</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-Destination Port: %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">ntohs</span><span class="p">(</span><span class="n">udp_hdr</span><span class="o">-&gt;</span><span class="n">dest</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-UDP Length      : %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">ntohs</span><span class="p">(</span><span class="n">udp_hdr</span><span class="o">-&gt;</span><span class="n">len</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\t</span><span class="s">|-UDP Checksum    : %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">ntohs</span><span class="p">(</span><span class="n">udp_hdr</span><span class="o">-&gt;</span><span class="n">check</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="cm">/**************************************************************************
</span></span></span><span class="line"><span class="cl"><span class="cm">* Function: void udp_payload(FILE *log_file, struct udphdr *udp_hdr)
</span></span></span><span class="line"><span class="cl"><span class="cm">* Description: Show data
</span></span></span><span class="line"><span class="cl"><span class="cm">* 
</span></span></span><span class="line"><span class="cl"><span class="cm">* Entry: buffer     data packet
</span></span></span><span class="line"><span class="cl"><span class="cm">*        buf_len    length of data packet
</span></span></span><span class="line"><span class="cl"><span class="cm">**************************************************************************/</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">udp_payload</span><span class="p">(</span><span class="n">FILE</span> <span class="o">*</span><span class="n">log_file</span><span class="p">,</span> <span class="k">struct</span> <span class="n">udphdr</span> <span class="o">*</span><span class="n">udp_hdr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">data</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">udp_hdr</span> <span class="o">+</span> <span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">udphdr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">Data</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">data_len</span> <span class="o">=</span> <span class="n">ntohs</span><span class="p">(</span><span class="n">udp_hdr</span><span class="o">-&gt;</span><span class="n">len</span><span class="p">)</span> <span class="o">-</span> <span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">udphdr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">data_len</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">!=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">16</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl">            <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34; %.2X &#34;</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="cm">/*****************************************************
</span></span></span><span class="line"><span class="cl"><span class="cm">* Main 
</span></span></span><span class="line"><span class="cl"><span class="cm">*****************************************************/</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">FILE</span><span class="o">*</span> <span class="n">log_file</span><span class="p">;</span>                             <span class="c1">// log file
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">struct</span> <span class="n">sockaddr</span> <span class="n">saddr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">sock_raw</span><span class="p">,</span> <span class="n">saddr_len</span><span class="p">,</span> <span class="n">buf_len</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">ret_value</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">done</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>               <span class="c1">// exit loop when done=1
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">int</span> <span class="n">udp</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>                <span class="c1">// udp packet count
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">    <span class="c1">// open a raw socket
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">sock_raw</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_PACKET</span><span class="p">,</span> <span class="n">SOCK_RAW</span><span class="p">,</span> <span class="n">htons</span><span class="p">(</span><span class="n">ETH_P_ALL</span><span class="p">));</span> 
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">sock_raw</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">printf</span><span class="p">(</span><span class="s">&#34;Error in socket</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// Allocate a block of memory for the receive buffer
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="mi">65536</span><span class="p">);</span> 
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">buffer</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">printf</span><span class="p">(</span><span class="s">&#34;Unable to allocate memory.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">close</span><span class="p">(</span><span class="n">sock_raw</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">memset</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">65536</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Create a log file for storing output
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">log_file</span> <span class="o">=</span> <span class="n">fopen</span><span class="p">(</span><span class="n">LOG_FILE</span><span class="p">,</span> <span class="s">&#34;w&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">log_file</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">printf</span><span class="p">(</span><span class="s">&#34;Unable to open %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">LOG_FILE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">free</span><span class="p">(</span><span class="n">buffer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">close</span><span class="p">(</span><span class="n">sock_raw</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">printf</span><span class="p">(</span><span class="s">&#34;starting .... %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">sock_raw</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">done</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Receive data packet
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">saddr_len</span> <span class="o">=</span> <span class="k">sizeof</span> <span class="n">saddr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">buf_len</span> <span class="o">=</span> <span class="n">recvfrom</span><span class="p">(</span><span class="n">sock_raw</span><span class="p">,</span> <span class="n">buffer</span><span class="p">,</span> <span class="mi">65536</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">saddr</span><span class="p">,</span> <span class="p">(</span><span class="n">socklen_t</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">saddr_len</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">buf_len</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">printf</span><span class="p">(</span><span class="s">&#34;Error in reading recvfrom function</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">ret_value</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">goto</span> <span class="n">QUIT</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">fflush</span><span class="p">(</span><span class="n">log_file</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Extracting the Ethernet header
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">if</span> <span class="p">(</span><span class="n">ethernet_header</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="n">buf_len</span><span class="p">)</span> <span class="o">!=</span> <span class="n">ETH_P_IP</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// drop the packet if network layer protocol is not IP
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Extracting the IP header
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">if</span> <span class="p">(</span><span class="n">ip_header</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="n">buf_len</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">17</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// drop packet if transport layer protocol is not UDP
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="n">fprintf</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\n</span><span class="s">**** UDP packet %02d*********************************</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">udp</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Write ethernet header into log file
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">log_ethernet_header</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="n">eth_hdr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Write IP header into log file
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">log_ip_header</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="n">ip_hdr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Extracting the UDP header and write into log file
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">udp_header</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="n">ip_hdr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// write UDP payload into log file
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">udp_payload</span><span class="p">(</span><span class="n">log_file</span><span class="p">,</span> <span class="n">udp_hdr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// exit when the count of received udp packets is more than 10
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">if</span> <span class="p">(</span><span class="o">++</span><span class="n">udp</span> <span class="o">&gt;=</span> <span class="mi">10</span><span class="p">)</span> <span class="n">done</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nl">QUIT</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">fclose</span><span class="p">(</span><span class="n">log_file</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">free</span><span class="p">(</span><span class="n">buffer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">close</span><span class="p">(</span><span class="n">sock_raw</span><span class="p">);</span>        <span class="c1">// close raw socket 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">printf</span><span class="p">(</span><span class="s">&#34;DONE!!!!</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">ret_value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>该程序使用raw_socket在数据链路层直接接收从物理层发过来的数据，数据不会经过各个协议层的处理；</p>
</li>
<li>
<p>在应用层进行socket进行网络编程时，端口号可以用于区分接收数据的应用程序，使用raw socket接收数据时，端口号没有用；</p>
</li>
<li>
<p>该程序将收到的udp数据包的以太网头、IP头、UDP头提取出来，和数据一起写入到文件udp_packets.log文件中；</p>
</li>
<li>
<p>该程序丢弃了除UDP包以外的所有其它数据包；</p>
</li>
<li>
<p>为了避免冗长的log文件，这个程序接收10个UDP数据包后会自动退出；</p>
</li>
<li>
<p>该程序经过扩展后可以成为一个简单的数据包嗅探器；</p>
</li>
<li>
<p><strong>编译程序</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">gcc -Wall receive_udp_packet.c -o receive_udp_packet
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p><strong>运行程序</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo ./receive_udp_packet
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>这个程序必须要使用root权限运行，因为使用了raw socket</li>
</ul>
</li>
<li>
<p><strong>测试程序</strong></p>
<ul>
<li>
<p>最好使用局域网中的两台机器(虚拟机)进行测试，因为在下面的测试方法中，从本机发送时，以太网头中的源和目的MAC地址可能会被填0；</p>
</li>
<li>
<p>假定A机的IP地址为 192.168.2.114，在A机运行程序receive_udp_packet程序；</p>
</li>
<li>
<p>我们从B机(与A机的IP不同)，发送数据：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> -n <span class="s2">&#34;udp packet 01&#34;</span> &gt; /dev/udp/192.168.2.114/8000
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> -n <span class="s2">&#34;udp packet 02&#34;</span> &gt; /dev/udp/192.168.2.114/8001
</span></span><span class="line"><span class="cl">......
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>8000和8001是端口号，可以是任意的；</p>
</li>
<li>
<p>连接在网络上的A机，有可能会从网络上收到其它的UDP包，所以A机启动receive_udp_packet程序后，要尽快在B机发出数据，否则可能你还没有发出数据，A机已经收到了10条UDP包并自动退出；</p>
</li>
<li>
<p>查看log文件，看看有没有你发出来的数据</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat udp_packets.log
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>在我的电脑上看到的是这样的：</p>
<p><img src="https://whowin.gitee.io/images/180002/receive_udp_packet.png" alt="收到的 udp 数据包"></p>
<center><b>图6：收到的 UDP 数据包</b></center>
</li>
</ul>
</li>
</ul>
<h2 id="欢迎订阅-网络编程专栏httpsblogcsdnnetwhowincategory_12180345html"><strong>欢迎订阅 <a href="https://blog.csdn.net/whowin/category_12180345.html">『网络编程专栏』</a></strong></h2>
<hr>
<p><strong>欢迎访问我的博客：https://whowin.cn</strong></p>
<p><strong>email: <a href="mailto:hengch@163.com">hengch@163.com</a></strong></p>
<p><img src="https://whowin.gitee.io/images/qrcode/sponsor-qrcode.png" alt="donation"></p>
<!-- CSDN
[img01]:https://img-blog.csdnimg.cn/img_convert/87f88f8da43e7323539e5ee03e6eba2b.png
[img02]:https://img-blog.csdnimg.cn/img_convert/50cbd29d4b42b3621fbb587a6d502a86.png
[img03]:https://img-blog.csdnimg.cn/img_convert/f8b16474c1fff6ce2763d5716a40bd34.png
[img04]:https://img-blog.csdnimg.cn/img_convert/e3fc7704cead9270cf3d8a51e0eaa179.png
[img05]:https://img-blog.csdnimg.cn/img_convert/a06cb0c8cb93f1484247605e6b53e6e7.png
[img06]:https://img-blog.csdnimg.cn/img_convert/d0d4a7b274a3ac9375baf47fc408f1e2.png
-->
    </div>

    <div class="post-copyright">
  <p class="copyright-item">
    <span class="item-title">文章作者</span>
    <span class="item-content">whowin</span>
  </p>
  <p class="copyright-item">
    <span class="item-title">上次更新</span>
    <span class="item-content">
        2022-12-07
        
    </span>
  </p>
  
  
</div>
<footer class="post-footer">
      <div class="post-tags">
          <a href="/tags/linux/">Linux</a>
          <a href="/tags/socket/">Socket</a>
          <a href="/tags/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/">网络编程</a>
          <a href="/tags/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82%E7%BC%96%E7%A8%8B/">数据链路层编程</a>
          <a href="/tags/raw-socket/">raw socket</a>
          </div>
      <nav class="post-nav">
        <a class="prev" href="/post/blog/network/0005-send-udp-via-linux-cli/">
            <i class="iconfont icon-left"></i>
            <span class="prev-text nav-default">如何在Linux命令行下发送和接收UDP数据包</span>
            <span class="prev-text nav-mobile">上一篇</span>
          </a>
        <a class="next" href="/post/blog/network/0001-how-to-get-ipv6-in-c/">
            <span class="next-text nav-default">C语言获取ipv6地址的三种方法</span>
            <span class="next-text nav-mobile">下一篇</span>
            <i class="iconfont icon-right"></i>
          </a>
      </nav>
    </footer>
  </article>
        </div>
        

  <span id="/post/blog/network/0002-link-layer-programming/" class="leancloud_visitors" data-flag-title="Linux下如何在数据链路层接收原始数据包">
		<span class="post-meta-item-text">文章阅读量 </span>
		<span class="leancloud-visitors-count">0</span>
		<p></p>
	  </span>
  <div id="vcomments"></div>
  <script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
  <script src='//unpkg.com/valine/dist/Valine.min.js'></script>
  <script type="text/javascript">
    new Valine({
        el: '#vcomments' ,
        appId: 'OFCGzCfJRUglzOdzrqMGkbTR-gzGzoHsz',
        appKey: 'v7P29kPAEbsmaavaYPNhGhnF',
        notify:  false ,
        verify:  false ,
        avatar:'mm',
        placeholder: '说点什么吧...',
        visitor:  true 
    });
  </script>

  

      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="social-links">
      <a href="mailto:hengch@163.com" class="iconfont icon-email" title="email"></a>
  <a href="https://whowin.gitee.io/index.xml" type="application/rss+xml" class="iconfont icon-rss" title="rss"></a>
</div>
<div class="copyright">
  <span class="power-by">
    由 <a class="hexo-link" href="https://gohugo.io">Hugo</a> 强力驱动
  </span>
  <span class="division">|</span>
  <span class="theme-info">
    主题 - 
    <a class="theme-link" href="https://github.com/olOwOlo/hugo-theme-even">Even</a>
  </span>

  <div class="busuanzi-footer">
    <span id="busuanzi_container_site_pv"> 本站总访问量 <span id="busuanzi_value_site_pv"><img src="/img/spinner.svg" alt="spinner.svg"/></span> 次 </span>
      <span class="division">|</span>
    <span id="busuanzi_container_site_uv"> 本站总访客数 <span id="busuanzi_value_site_uv"><img src="/img/spinner.svg" alt="spinner.svg"/></span> 人 </span>
  </div>

  <span class="copyright-year">
    &copy; 
    2022 - 
    2024<span class="heart"><i class="iconfont icon-heart"></i></span><span>whowin</span>
  </span>
</div>

    </footer>

    <div class="back-to-top" id="back-to-top">
      <i class="iconfont icon-up"></i>
    </div>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/slideout@1.0.1/dist/slideout.min.js" integrity="sha256-t+zJ/g8/KXIJMjSVQdnibt4dlaDxc9zXr/9oNPeWqdg=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.js" integrity="sha256-XVLffZaxoWfGUEbdzuLi7pwaUJv1cecsQJQqGLe7axY=" crossorigin="anonymous"></script>



<script type="text/javascript" src="/js/main.min.64437849d125a2d603b3e71d6de5225d641a32d17168a58106e0b61852079683.js"></script>
  <script type="text/javascript">
    window.MathJax = {
      tex: {
        inlineMath: [['$','$'], ['\\(','\\)']],
        }
    };
  </script>
  <script async src="https://cdn.jsdelivr.net/npm/mathjax@3.0.5/es5/tex-mml-chtml.js" integrity="sha256-HGLuEfFcsUJGhvB8cQ8nr0gai9EucOOaIxFw7qxmd+w=" crossorigin="anonymous"></script>








</body>
</html>
